﻿namespace Webinator.Toolboxes
{
    using System.Diagnostics.CodeAnalysis;
    using Enums;
    using Impls;

    using Webinator.Interfaces;

    [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Reviewed. Suppression is OK here.")]
    public class JavascriptToolbox : IJavascript
    {
        private readonly IWebManager _webManager;

        public JavascriptToolbox(IWebManager webManager)
        {
            _webManager = webManager;
        }

        public void BeginListeningForPageSubmit()
        {
            // Begins javascript post detection
            string js = @"{" +
                        @"  function waitingForPost()" +
                        @"  { " +
                        @"    var temp=document.getElementById('WebinatorJsListener');" +
                        @"    temp.parentNode.removeChild(temp);" +
                        @"    var javascriptRunning=document.createElement('div'); " +
                        @"    javascriptRunning.id='WebinatorJsListenerPosting';" +
                        ////@"    javascriptRunning.style.cssText='background-color:yellow; border:2px dotted yellow;';" +
                        @"    b=document.getElementsByTagName('body')[0];" +
                        @"    b.appendChild(javascriptRunning);" +
                        string.Format(Scripts.Message, "Post detected...", 2000) +
                        @"  }" +
                        @"  var waitingForJavascript=document.createElement('div'); " +
                        @"  waitingForJavascript.id='WebinatorJsListener';" +
                        ////@"  waitingForJavascript.style.cssText='background-color:red; border:2px dotted red;';" +
                        @"  b=document.getElementsByTagName('body')[0];" +
                        @"  b.appendChild(waitingForJavascript);" +
                        @"  var originalOnBeforeUnload = window.onbeforeunload;" +
                        @"  if (typeof window.onbeforeunload != 'function') { window.onbeforeunload = waitingForPost; } " +
                        @"  else { window.onbeforeunload = function() { waitingForPost(); originalOnBeforeUnload(); } }" +
                        @"}";

            RunJavaScript(js);
        }

        public bool PageIsSubmitting()
        {
            var pageIsSubmitting = false;

            // If WebinatorJsListenerPosting is found then the page is doing a post
            var listenerExists = _webManager.Exists(new Locator(FindBy.Id, "WebinatorJsListenerPosting"), 1);
            if (listenerExists)
            {
                pageIsSubmitting = true;
            }

            // If WebinatorJsListener is not found, then page has already posted
            listenerExists = _webManager.Exists(new Locator(FindBy.Id, "WebinatorJsListener"), 1);
            if (!listenerExists)
            {
                pageIsSubmitting = true;
            }

            return pageIsSubmitting;
        }

        public void WaitForPageToFinishSubmitting(int timeoutInMilliseconds = 10000)
        {
            // Wait for post start
            var notExists = new Condition.NotExists
            {
                Locator = new Locator(FindBy.Id, "WebinatorJsListenerPosting"),
                TimeoutInMilliseconds = timeoutInMilliseconds,
            };
            _webManager.Wait(notExists);

            // Signal post completion with javascript
            var js = @"{" + 
                     @"    var temp=document.createElement('div'); " +
                     @"    temp.id='WebinatorJsListenerPosted';" +
                     ////@"    temp.style.cssText='background-color:green; border:2px dotted green;';" +
                     @"    b=document.getElementsByTagName('body')[0];" +
                     @"    b.appendChild(temp);" +
                     @"}";
            DisplayMessageInBrowser("Post completed.");
            RunJavaScript(js);

            // Wait for post to complete
            var exists = new Condition.Exists 
            {
                Locator = new Locator(FindBy.Id, "WebinatorJsListenerPosted"),
                TimeoutInMilliseconds = timeoutInMilliseconds,
            };
            _webManager.Wait(exists);
            js = @"{var temp=document.getElementById('WebinatorJsListenerPosted'); temp.parentNode.removeChild(temp);}";
            RunJavaScript(js);
        }

        public void StopListeningForPageSubmit()
        {
            try
            {
                const string Js = @"{var temp=document.getElementById('WebinatorJsListener'); temp.parentNode.removeChild(temp);}";
                RunJavaScript(Js);
            }
            catch
            {
            }
        }

        public void InjectJquery()
        {
            // Source: http://www.learningjquery.com/2009/04/better-stronger-safer-jquerify-bookmarklet
            // Modified to remove the messaging and just inject JQuery
            RunJavaScript(Scripts.JQuery);
        }

        public bool NetworkActive()
        {
            InjectJquery();
            return (bool)_webManager.EvalJavaScript("return jQuery.active > 0");
        }

        public void RunJavaScript(string js)
        {
            _webManager.RunJavaScript(js);
        }

        /// <summary>
        /// Displays a message in the browser.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="interval">How long to display the message in milliseconds.</param>
        public void DisplayMessageInBrowser(string message, int interval = 2500)
        {
            RunJavaScript(string.Format(Scripts.Message, message, interval));
        }

        public string GetJavascriptAddCookie(JavascriptCookie cookie)
        {
            return GetJavascriptSetCookie(cookie);
        }

        public string GetJavascriptDeleteCookie(string name)
        {
            return string.Format(@"{{document.cookie = ""{0}="" + "";path=/;expires=Thu, 01-Jan-1970 00:00:01 GMT"";}}", name);
        }

        // Won't work on WatiN - return statement must be removed.
        public string GetJavascriptGetCookie(string name)
        {
            var javascript =
                @"function GetCookie() { var a_all_cookies = document.cookie.split( ';' ); var a_temp_cookie = ''; var cookie_name = ''; var cookie_value = ''; var b_cookie_found = false;" +
                @"for ( i = 0; i < a_all_cookies.length; i++ ) { a_temp_cookie = a_all_cookies[i].split( '=' );" +
                string.Format(@"cookie_name = a_temp_cookie[0].replace(/^\s+|\s+$/g, ''); if ( cookie_name == ""{0}"" ) {{", name) +
                @"b_cookie_found = true; if ( a_temp_cookie.length > 1 ) { cookie_value = unescape( a_temp_cookie[1].replace(/^\s+|\s+$/g, ''));}" +
                @"return cookie_value; break; } a_temp_cookie = null; cookie_name = ''; } if ( !b_cookie_found ) { return null; } } return GetCookie();";
            return javascript;
        }

        public string GetJavascriptSetCookie(JavascriptCookie cookie)
        {
            var javascript = 
                string.Format(@"{{document.cookie = ""{0}="" + escape(""{1}"") + ", cookie.Name, cookie.Value) +
                string.Format(@"("";path={0}"") + ("";domain={1}"");}}", cookie.Path, cookie.Domain);
            return javascript;
        }
    }
}
